#pragma once
#include <cstring>
#include <sys/socket.h>
#include <net/if.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <vector>
#include <stdexcept>
#include <dirent.h>
#include <algorithm>
#include <random>
#include <fmt/format.h>
#include <sstream>
#include <atomic>
#include <fmtlog/fmtlog.h>

namespace MY_MQ
{

class UUIDHelper {
public:
    // 自动获取系统中的第一个有效网络接口的 MAC 地址
    static std::string getMACAddress() {
        std::vector<std::string> interfaces = getNetworkInterfaces();
        
        for (const auto& interface : interfaces) {
            //去除本地环回
            if(interface != "lo")
            {
                try {
                return getMACAddress(interface);
                } catch (const std::runtime_error&) {
                    // 如果获取失败，尝试下一个接口
                    logw("Failed to get MAC address for interface: {}", interface);
                    continue;
                }
            }
        }
        logw("No valid network interface found, generating random MAC address.");
        return generateRandomMACAddress();
    }

    static std::string getMACAddress(const std::string& interface) {
        int fd = socket(AF_INET, SOCK_DGRAM, 0);
        if (fd == -1) {
            throw std::runtime_error("Failed to create socket");
        }

        struct ifreq ifr;
        std::strncpy(ifr.ifr_name, interface.c_str(), IFNAMSIZ-1);

        if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) {
            close(fd);
            throw std::runtime_error("Failed to get MAC address for interface: " + interface);
        }

        close(fd);

        unsigned char mac[12];
        std::memcpy(mac, ifr.ifr_hwaddr.sa_data, 12);

        std::stringstream macStr;
        for (int i = 0; i < 6; ++i) {
            macStr << fmt::format("{:02x}", mac[i]);
        }

        return macStr.str();
    }

    static std::vector<std::string> getNetworkInterfaces() {
        std::vector<std::string> interfaces;
        DIR* dir = opendir("/sys/class/net/");
        if (dir != nullptr) {
            struct dirent* ent;
            while ((ent = readdir(dir)) != nullptr) {
                if (ent->d_type == DT_DIR || ent->d_type == DT_LNK) {
                    std::string ifaceName = ent->d_name;
                    if (ifaceName != "." && ifaceName != "..") {
                        interfaces.push_back(ifaceName);
                    }
                }
            }
            closedir(dir);
        } else {
            throw std::runtime_error("Failed to open /sys/class/net/");
        }
        return interfaces;
    }

    static std::string shuffleMACAddress(const std::string& macAddress) {
        std::string shuffledMAC = macAddress;
        std::random_device rd;
        std::mt19937 g(rd());
        std::shuffle(shuffledMAC.begin(), shuffledMAC.end(), g);
        return shuffledMAC;
    }

    static std::string uuidWithShuffledMAC() {
        std::string macAddress = getMACAddress();
        std::string shuffledMAC = shuffleMACAddress(macAddress);

        std::random_device rd;
        std::mt19937_64 generator(rd());
        std::uniform_int_distribution<int> distribution(0, 255);

        auto to_hex = [&](int value) {
            return fmt::format("{:02x}", value);
        };

        // Create a UUID with the format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
        std::string uuid;
        uuid.reserve(36);

        for (int i = 0; i < 8; ++i) {
            uuid += to_hex(distribution(generator));
            if (i == 3 || i == 5 || i == 7) {
                uuid += "-";
            }
        }

        static std::atomic<size_t> seq(1);
        size_t num = seq.fetch_add(1);
        for (int i = 7; i >= 0; --i) {
            uuid += to_hex((num >> (i * 8)) & 0xff);
            if (i == 6) uuid += "-";
        }

        // Append the shuffled MAC address (12 hex digits)
        uuid += "-" + shuffledMAC;

        return uuid;
    }

private:
    static std::string generateRandomMACAddress() {
        std::random_device rd;
        std::mt19937 gen(rd());
        std::uniform_int_distribution<> dis(0, 255);

        std::stringstream ss;
        for (int i = 0; i < 6; ++i) {
            ss << fmt::format("{:02x}", dis(gen));
        }

        return ss.str();
    }
};

};
